/* 
   Copyright 2012 Ryne Okimoto

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
 */
   
package delegate;

import java.awt.Component;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentEvent;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.filechooser.FileNameExtensionFilter;

import panels.IngredientPanel;

import recipe.RecipeData;

import manager.FileManager;
import model.DataManagerModel;

/**
 * Class - CreateEditViewController
 * Description - Abstract class for the edit and create views
 * @author Ryne Okimoto
 */

@SuppressWarnings("serial")
public abstract class CreateEditViewController extends JFrame{
	
	// Class data
	private static String DEFAULT_RECIPE_NAME  = "<Enter recipe name>";
	private static String DEFAULT_CATEGORY     = "<Enter category>";
	private static String DEFAULT_TAGS         = "<Enter tags>";
	private static String DEFAULT_INGREDIENTS  = "<Enter ingredients>";
	private static String DEFAULT_INSTRUCTIONS = "<Enter instructions>";
	
	private DataManagerModel dataModel      = null;
	private FileManager      dataManager    = null;
	private RecipeData       recipe         = null;
	
	private JLabel           lblRecipeName  = new JLabel("Recipe name");
	private JLabel           lblCategory    = new JLabel("Category");
	private JLabel           lblTags        = new JLabel("Tags");
	private JLabel           lblIngredients = new JLabel("Ingredients");
	private JLabel           lblInstructions = new JLabel("Instructions");
	private JLabel           lblImage       = new JLabel("Image");
	
	private JButton          btnDone        = new JButton("Save");
	private JButton          btnCancel      = new JButton("Cancel");
	private JButton          btnImageBrowse = new JButton("Browse");
	
	private JTextField       txtRecipeName  = new JTextField(DEFAULT_RECIPE_NAME, 30);
	private JTextField       txtCategory    = new JTextField(DEFAULT_CATEGORY, 15);
	private JTextField       txtTags        = new JTextField(DEFAULT_TAGS, 30);
	private JTextField       txtImage       = new JTextField(20);
	private IngredientPanel  pnlIngredients = new IngredientPanel();
	private JPanel           pnlImage       = new JPanel();
	private JPanel           pnlSaveCancel  = new JPanel();
	private JTextArea        txaInstructions = new JTextArea(DEFAULT_INSTRUCTIONS, 10, 30);
	
	private File             imageFile      = null;
	private File             saveFile       = null;
	private BufferedImage    bi             = null;
	
	/**
	 * Constructor
	 * Description - Instantiates the view using the data model
	 * @param model
	 */
	public CreateEditViewController(String title, DataManagerModel model, FileManager manager)
	{
		// Set model for viewController
		dataModel = model;
		dataManager = manager;
		if(manager != null){
			recipe = manager.getData();
		}
		
		// Set layout and properties
		JPanel view = new JPanel();
		view.setLayout(new GridBagLayout());
		this.setResizable(false);
		
		setComponentProperties();
		
		// Add components
		if(recipe != null){
			txtRecipeName.setText(recipe.getRecipeName());
			txtCategory.setText(recipe.getCategory());
			txaInstructions.setText(recipe.getInstructions());
			pnlIngredients.setRows(recipe.getListOfIngredients());
			txtTags.setText(recipe.getTags());
			txtImage.setText(recipe.getImageFileName());
		}
		
		view.add(lblRecipeName, setConstraints(0, 0, true));
		view.add(lblCategory, setConstraints(0, 1, false));
		view.add(lblTags, setConstraints(0, 2, false));
		view.add(lblIngredients, setConstraints(0, 3, false));
		view.add(lblInstructions, setConstraints(0, 4, false));
		view.add(lblImage, setConstraints(0, 5, false));
		
		
		view.add(txtRecipeName, setConstraints(1, 0, true));
		view.add(txtCategory, setConstraints(1, 1, false));
		view.add(txtTags, setConstraints(1, 2, false));
		view.add(pnlIngredients, setIngredientsConstraints(1, 3));
		view.add(txaInstructions, setInstructionsConstraints(1, 4));
		view.add(pnlImage, setConstraints(1, 5, false));

		view.add(pnlSaveCancel, setConstraints(3, 7, false));
		
		// Register listeners
		btnDone.addActionListener(new DoneClickedListener());
		btnCancel.addActionListener(new CancelClickedListener());
		btnImageBrowse.addActionListener(new BrowseClickedListener());
		txtRecipeName.addFocusListener(new TextFocusListener());
		txtCategory.addFocusListener(new TextFocusListener());
		txtTags.addFocusListener(new TextFocusListener());
		txaInstructions.addFocusListener(new TextFocusListener());
		
		this.setContentPane(view);
		this.setTitle(title);
		this.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
		this.pack();
	} // Constructor
	
	private void setComponentProperties(){
		btnDone.setFocusable(true);
		btnCancel.setFocusable(true);
		txtRecipeName.setFocusable(true);
		txtCategory.setFocusable(true);
		txtTags.setFocusable(true);
		
		pnlImage.add(txtImage);
		pnlImage.add(btnImageBrowse);
		
		pnlSaveCancel.add(btnDone);
		pnlSaveCancel.add(btnCancel);
		
		txtImage.setFocusable(true);
		txtImage.setEditable(false);
		
		txaInstructions.setWrapStyleWord(true);
		txaInstructions.setLineWrap(true);
		txaInstructions.setFocusable(true);
	}
	
	private GridBagConstraints setConstraints(int col, int row, boolean isTopOrBottom){
		GridBagConstraints gbc = new GridBagConstraints();
		Insets in;
		
		if(isTopOrBottom){
			in = new Insets(10, 10, 10, 10);
		}
		else{
			in = new Insets(10, 10, 0, 10);
		}
		
		gbc.gridx = col;
		gbc.gridy = row;
		gbc.insets = in;
		
		return gbc;
	}
	
	private GridBagConstraints setInstructionsConstraints(int col, int row){
		GridBagConstraints gbctxaInstructions = new GridBagConstraints();
		
		gbctxaInstructions.gridx = col;
		gbctxaInstructions.gridy = row;
		gbctxaInstructions.fill = GridBagConstraints.HORIZONTAL;
		gbctxaInstructions.insets = new Insets(10, 10, 10, 10);
		gbctxaInstructions.gridwidth = 3;
		
		return gbctxaInstructions;
	}
	
	private GridBagConstraints setIngredientsConstraints(int col, int row){
		GridBagConstraints gbcTxaIngredients = new GridBagConstraints();
		
		gbcTxaIngredients.gridx = col;
		gbcTxaIngredients.gridy = row;
		gbcTxaIngredients.fill = GridBagConstraints.HORIZONTAL;
		gbcTxaIngredients.insets = new Insets(10, 10, 0, 10);
		gbcTxaIngredients.gridwidth = 3;
		
		return gbcTxaIngredients;
	}
	
	private boolean saveImage(){
		boolean isSaved = false;
		try{
			if(bi != null && saveFile != null){
				ImageIO.write(bi, "jpg", saveFile);
				isSaved = true;
			}
		}
		catch(IOException io){
			io.printStackTrace();
		}
		
		return isSaved;
	}
	
	/**
	 * Method - validateInputFields
	 * Description - Checks all input fields for completion
	 * @return boolean
	 */
	private boolean validateInputFields(){
		boolean isInputOK = true;
		StringBuilder errorMessage = new StringBuilder("Please enter information for:\n");
		
		if(txtRecipeName.getText().equalsIgnoreCase(DEFAULT_RECIPE_NAME)){
			errorMessage.append("recipe name\n");
			isInputOK = false;
		}
		
		if(txtCategory.getText().equalsIgnoreCase(DEFAULT_CATEGORY)){
			errorMessage.append("category\n");
			isInputOK = false;
		}
		
		if(txtTags.getText().equalsIgnoreCase(DEFAULT_TAGS)){
			errorMessage.append("tags\n");
			isInputOK = false;
		}
		// TODO validate ingredient input
		/*
		if(txaIngredients.getText().equalsIgnoreCase(DEFAULT_INGREDIENTS)){
			errorMessage.append("ingredients\n");
			isInputOK = false;
		}
		*/
		
		if(txaInstructions.getText().equalsIgnoreCase(DEFAULT_INSTRUCTIONS)){
			errorMessage.append("instructions\n");
			isInputOK = false;
		}
			
		if(!isInputOK){
			JOptionPane.showMessageDialog(this, errorMessage.toString(), 
					"Incomplete fields", JOptionPane.ERROR_MESSAGE);
		}
		
		return isInputOK;
	}
	
	/**
	 * Class - CancelClickedListener
	 * Description - Listener for the cancel button. Closes the view.
	 */
	private class CancelClickedListener implements ActionListener{
		
		public void actionPerformed(ActionEvent e){
			CreateEditViewController.this.dispose();
			
			// If cancel clicked from edit view
			// show open view
			if(dataManager != null){
				OpenRecipeViewController openView = new OpenRecipeViewController(
						CreateEditViewController.this.dataModel,
						CreateEditViewController.this.dataManager);
				openView.setVisible(true);
			}
		}
	}
	
	/**
	 * Class - DoneClickedListener
	 * Description - Validates the field data and adds a filemanager
	 *               to the data model
	 */
	private class DoneClickedListener implements ActionListener
	{
		public void actionPerformed(ActionEvent e)
		{
			if(validateInputFields()){
				// Check for initialized manager (for edit view)
				if(dataManager != null){
					
					dataModel.setCurrentFileManager(dataManager);
					dataModel.modifyFileManager(txtRecipeName.getText(), txtCategory.getText(), 
							pnlIngredients.getIngredientString(), txaInstructions.getText(), 
							txtTags.getText(), txtImage.getText());
					
					saveImage();
					
					if(dataManager.closeFile()){
						JOptionPane.showMessageDialog(CreateEditViewController.this, "Edit success!");
						CreateEditViewController.this.dispose();
						OpenRecipeViewController openView = new OpenRecipeViewController(
								CreateEditViewController.this.dataModel, 
								CreateEditViewController.this.dataManager);
						openView.setVisible(true);
					}
					
				}
				// Check for initialized model (for create view)
				else if(dataModel != null){
					if(dataModel.addFileManager
					(txtRecipeName.getText(), txtCategory.getText(), 
					pnlIngredients.getIngredientString(), txaInstructions.getText(), 
					txtTags.getText(), txtImage.getText())){
						
						saveImage();
									
						JOptionPane.showMessageDialog(CreateEditViewController.this, "Recipe created!");
						CreateEditViewController.this.dispose();
					}	
				}
			}
		}
	}
	
	/**
	 * Class - BrowseClickedListener
	 * Description - ActionListener for the browse button
	 */
	private class BrowseClickedListener implements ActionListener{
		
		public void actionPerformed(ActionEvent e){
			
			JFileChooser browser = new JFileChooser("~");
			FileNameExtensionFilter filter = new FileNameExtensionFilter("JPEG file", "jpg", "jpeg");
			browser.setFileFilter(filter);
			
			int option = browser.showOpenDialog(CreateEditViewController.this);
			
			if(option == JFileChooser.APPROVE_OPTION){
				// Save file to database
				try{
					imageFile = browser.getSelectedFile();
					saveFile = new File("./rcp_db/Img_Files/" + imageFile.getName());
					bi = ImageIO.read(imageFile);
					
					CreateEditViewController.this.txtImage.setText(imageFile.getName());
				}
				catch(IOException io){
					io.printStackTrace();
				}
			}
		}
	}
	
	/**
	 * Class - TextFocusListener
	 * Description - Listens for focus changes on components
	 */
	private class TextFocusListener implements FocusListener{
		
		/**
		 * Method - focusGained
		 * Description - Clears text in component if it is default
		 */
		public void focusGained(FocusEvent e){
			ComponentEvent ce = new ComponentEvent(e.getComponent(), e.getID());
			Component temp = ce.getComponent();
			if(temp instanceof JTextField){
				JTextField tf = (JTextField) temp;
				if(
					tf.getText().equalsIgnoreCase(DEFAULT_RECIPE_NAME) ||
					tf.getText().equalsIgnoreCase(DEFAULT_TAGS) ||
					tf.getText().equalsIgnoreCase(DEFAULT_CATEGORY)){
					tf.setText("");
				}
				
			}
			else if(temp instanceof JTextArea){
				JTextArea ta = (JTextArea) temp;
				if(
					ta.getText().equalsIgnoreCase(DEFAULT_INSTRUCTIONS) ||
					ta.getText().equalsIgnoreCase(DEFAULT_INGREDIENTS)
				){
					ta.setText("");
				}
			}
		}
		
		/**
		 * Method - focusLost
		 * Description - Resets text in component if nothing was entered
		 */
		public void focusLost(FocusEvent e){
			ComponentEvent ce = new ComponentEvent(e.getComponent(), e.getID());
			Component temp = ce.getComponent();
			
			if(temp instanceof JTextField){
				JTextField tf = (JTextField) temp;
				if(tf.equals(txtRecipeName) && tf.getText().isEmpty()){
					tf.setText(DEFAULT_RECIPE_NAME);
				}
				else if(tf.equals(txtCategory) && tf.getText().isEmpty()){
					tf.setText(DEFAULT_CATEGORY);
				}
				else if(tf.equals(txtTags) && tf.getText().isEmpty()){
					tf.setText(DEFAULT_TAGS);
				}	
			}	
			else if(temp instanceof JTextArea){
				JTextArea ta = (JTextArea) temp;
				if(ta.equals(txaInstructions) && ta.getText().isEmpty()){
					ta.setText(DEFAULT_INSTRUCTIONS);
				}
			}
		}
	}
} // CreateEditViewController
